package com.oa.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.oa.back.ResponseBack;
import com.oa.common.base.Page;
import com.oa.common.base.Pageable;
import com.oa.common.dto.UserDto;
import com.oa.common.enums.CodeStatus;
import com.oa.common.enums.UserStatus;
import com.oa.common.utils.CookieUtil;
import com.oa.common.utils.EncryptUtils;
import com.oa.common.vo.Propal;
import com.oa.dao.BaseDao;
import com.oa.dao.UserDao;
import com.oa.entities.*;
import com.oa.service.*;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.SerializationUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.security.auth.Subject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.*;

@Service
public class UserServiceImpl extends UndeleteServiceImpl<Long, User> implements UserService {

    @Qualifier("redisServiceImpl")
    @Autowired
    private RedisService redisService;

    @Autowired
    private RSAService rsaService;

    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    private UserDao dao;

    @Autowired
    private DepartmentService departmentService;

    @Autowired
    private PositionService positionService;

    @Autowired
    private UserInfoService infoService;

    @Autowired
    private RoleService roleService;

    @Override
    protected BaseDao<Long, User> getSelfDao() {
        return dao;
    }

    @Override
    public void setClass(Class<User> clazz) {

    }

    @Override
    @Transactional
    public ResponseBack<String> login(HttpServletRequest request, HttpServletResponse response, String username, String password, String code) {
        if (StringUtils.isEmpty(username)) {
            return ResponseBack.fial(CodeStatus.USERNAME_NOTNULL.getResponseStatus());
        }
        if (StringUtils.isEmpty(password)) {
            return ResponseBack.fial(CodeStatus.PASSWORD_NOTNULL.getResponseStatus());
        }
        if (!redisService.validateVerify(request.getSession().getId(), code)) {
            return ResponseBack.fial(CodeStatus.VERIFY_FAIL.getResponseStatus());
        }
        password = rsaService.RSADecrypt(password, request);
        password = EncryptUtils.encodeMD5(password);
        User user = dao.findByUsername(username);
        if (user == null) {
            return ResponseBack.fial(CodeStatus.MEMBER_UNDERFIND.getResponseStatus());
        }
        if (!user.getPassword().equals(password)) {
            return ResponseBack.fial(CodeStatus.PASSWORD_FAIL.getResponseStatus());
        }
        if (!user.getManager()) {
            if (user.getInfo() != null) {
                if (user.getInfo().getUserStatus() == UserStatus.DIMISSION.getCode()) {
                    return ResponseBack.fial(CodeStatus.USER_DISMISSION.getResponseStatus());
                }
            }
        }
        Propal propal = new Propal(user, request.getLocalAddr(),password);
        user.setLoginIp(request.getLocalAddr());
        user.setLoginTime(System.currentTimeMillis());
        update(user);
        String loginKey = User.PERSON_LOGIN_KEY + user.getId();
        String vo = JSONObject.toJSONString(propal);
        redisService.saveLogin(loginKey, vo);
        HttpSession session = request.getSession();
        Map<String, Object> attributes = new HashMap<String, Object>();
        Enumeration<?> keys = session.getAttributeNames();
        while (keys.hasMoreElements()) {
            String key = (String) keys.nextElement();
            attributes.put(key, session.getAttribute(key));
        }
        session.invalidate();
        session = request.getSession();
        for (Map.Entry<String, Object> entry : attributes.entrySet()) {
            session.setAttribute(entry.getKey(), entry.getValue());
        }
        session.setAttribute(User.USER_COOKIE_NAME, propal);
        CookieUtil.addCookie(response, User.USER_COOKIE_NAME, username, 28800);
        return ResponseBack.success(null);
    }

    @Override
    @Transactional
    public void init() {
        if (countByFilter(null) == 0) {
            User person = new User();
            person.setUsername("admin");
            person.setPassword(EncryptUtils.encodeMD5("888888"));
            person.setManager(true);
            person.setCreateTime(System.currentTimeMillis());
            save(person);
        }
    }

    @Override
    public User findByUsername(String username) {
        return dao.findByUsername(username);
    }

    @Override
    @Transactional
    public List<String> findById(Long id) {
        User user = get(id);
        Set<Role> roles = user.getRoles();
        List<String> authorities = new ArrayList<>();
        for (Role role : roles) {
            authorities.addAll(role.getAuthorities());
        }
        return authorities;
    }

    @Override
    @Transactional
    public Page<User> findByPage(Pageable pageable, String key) {
        return dao.findPage(pageable, key);
    }

    @Override
    public Boolean validateByDepartment(Long departmentId) {
        return dao.validateByDepartment(departmentId);
    }

    @Override
    public Boolean validateByRole(Long roleId) {
        return dao.validateByRole(roleId);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public ResponseBack<String> submit(String params) {
        if (StringUtils.isEmpty(params)) {
            return ResponseBack.fial(CodeStatus.PARAMS_FAIL.getResponseStatus());
        }
        UserDto dto = JSONObject.parseObject(params, UserDto.class);
        if (dto == null) {
            return ResponseBack.fial(CodeStatus.PARAMS_FAIL.getResponseStatus());
        }
        logger.warn("提交的信息:" + dto);
        if (StringUtils.isEmpty(dto.getUsername())) {
            return ResponseBack.fial(CodeStatus.USERNAME_NOTNULL.getResponseStatus());
        }
        if (validateUsername(dto.getUsername(), null)) {
            return ResponseBack.fial(CodeStatus.USER_USERNAME_EXIST.getResponseStatus());
        }
        if (StringUtils.isEmpty(dto.getPhone())) {
            return ResponseBack.fial(CodeStatus.USER_PHONE_NOTNULL.getResponseStatus());
        }
        if (validatePhone(dto.getPhone(), null)) {
            return ResponseBack.fial(CodeStatus.USER_PHONE_EXIST.getResponseStatus());
        }
        if (validateEmail(dto.getEmail(), null)) {
            return ResponseBack.fial(CodeStatus.USER_EMAIL_EXIST.getResponseStatus());
        }
        if (StringUtils.isEmpty(dto.getRealName())) {
            return ResponseBack.fial(CodeStatus.USER_REALNAME_NOTNULL.getResponseStatus());
        }
        Department department = departmentService.get(dto.getDepartmentId());
        if (department == null) {
            return ResponseBack.fial(CodeStatus.DEPARTMENT_UNDERFUND.getResponseStatus());
        }
        Role role = roleService.get(dto.getRoleId());
        if (role == null) {
            return ResponseBack.fial(CodeStatus.ROLE_UNDERFUND.getResponseStatus());
        }
        Position position = positionService.get(dto.getPositionId());
        if (position == null) {
            return ResponseBack.fial(CodeStatus.POSITION_UNDERFUND.getResponseStatus());
        }
        User user = new User();
        user.setUsername(dto.getUsername());
        user.setEmail(dto.getEmail());
        user.setPhone(dto.getPhone());
        user.setPassword(EncryptUtils.encodeMD5("888888"));
        user.setCreateTime(System.currentTimeMillis());
        user.setManager(false);
        Set<Role> roles = new HashSet<>();
        roles.add(role);
        user.setRoles(roles);
        save(user);
        UserInfo userInfo = new UserInfo();
        userInfo.setAddress(dto.getAddress());
        userInfo.setDepartment(department);
        userInfo.setUserStatus(UserStatus.JOB.getCode());
        userInfo.setDepartmentId(dto.getDepartmentId());
        userInfo.setGender(dto.getSex());
        userInfo.setPosition(position);
        userInfo.setPortrait(dto.getPortrait());
        userInfo.setJobTime(dto.getJobTime());
        userInfo.setPostcode(dto.getPostcode());
        userInfo.setPicture(dto.getPicture());
        userInfo.setTelphone(dto.getTelphone());
        userInfo.setUser(user);
        userInfo.setRealName(dto.getRealName());
        infoService.save(userInfo);
        return ResponseBack.success(null);
    }

    @Override
    public Boolean validateUsername(String username, Long id) {
        return dao.validateUsername(username, id);
    }

    @Override
    public Boolean validatePhone(String phone, Long id) {
        return dao.validatePhone(phone, id);
    }

    @Override
    public Boolean validateEmail(String email, Long id) {
        return dao.validateEmail(email, id);
    }

    @Override
    @Transactional
    public ResponseBack<String> dimission(Long id) {
        User user = get(id);
        if (user == null) {
            return ResponseBack.fial(CodeStatus.USER_DISMISSION.getResponseStatus());
        }
        user.getInfo().setUserStatus(UserStatus.DIMISSION.getCode());
        update(user);
        return ResponseBack.success(null);
    }

    @Override
    public User getCurrent() {
        org.apache.shiro.subject.Subject subject=SecurityUtils.getSubject();
        String username= (String) subject.getPrincipal();
        return findByUsername(username);
    }
}
